
GuildFilter = LibStub("AceAddon-3.0"):NewAddon("GuildFilter", "AceHook-3.0")

-- locals
local frame -- our frame
local filteredMembers = {} -- filtered listing of guildmember IDs

function GuildFilter:OnEnable()
	self.filteredMembers = filteredMembers
	self.filter = nil
	self.filters = {
		["strings"] = {},
		["levels"] = {},
	}
	self:SecureHook("GuildStatus_Update")
	self:GuildStatus_Update() -- LoD handling
end

function GuildFilter:OnDisable()
	self:HideGUI()
end

local function emptyTable(t)
	for k, v in pairs(t) do
		if type(v) == "table" then
			emptyTable(v)
		end
		t[k] = nil
	end
end

function GuildFilter:SetFilter(filter)
	self.filter = filter
	emptyTable(self.filters["strings"])
	emptyTable(self.filters["levels"])
	if filter then
		local found
		for fil in filter:gmatch("[^ ]+") do
			found = false
			for chunk in fil:gmatch('([%d%p]+)') do
				-- check for numbers
				if tonumber(chunk) then -- '68'
					found = true
					table.insert(self.filters["levels"], { ["="] = tonumber(chunk) } )
				elseif chunk:match('%+') then -- '40+'
					found = true
					table.insert(self.filters["levels"], { [">="] = tonumber(chunk:match('%d+')) } )
				elseif chunk:match('%-$') then -- '30-'
					found = true
					table.insert(self.filters["levels"], { ["<="] = tonumber(chunk:match('%d+')) } )
				elseif chunk:match('%d+%-%d+') then -- '20-47'
					found = true
					local low, high = tonumber(chunk:match('(%d+)%-(%d+)'))
					table.insert(self.filters["levels"], { ["<="] = high } )
					table.insert(self.filters["levels"], { [">="] = low } )
				end
			end
			if not found then -- not a number so treat as a string
				table.insert(self.filters["strings"], fil:lower())
			end
		end
	end
	-- reset the scroll offset on the GUI
	FauxScrollFrame_SetOffset(GuildListScrollFrame, 0)
	-- Update the frame
	self:GuildStatus_Update()
end

-- this hook is basically a stripped down and modified copy of the blizzard function that we hook
function GuildFilter:GuildStatus_Update()

	-- check if the correct frame is visible, if not HIDE, this is mainly for LoD Handling
	if not GuildFrame:IsVisible() then return end
	
	self:ShowGUI()

	if not self.filter then return end -- bail out if we're not filtering anything

	local numGuildMembers = GetNumGuildMembers()
	local name, rank, rankIndex, level, class, zone, note, officernote, online, status
	local button, buttonText, classTextColor
	local guildIndex

	emptyTable(filteredMembers)
	local success = true
	-- loop over the guildmembers filtering them for showing.
	for i=1, numGuildMembers, 1 do
		success = true
		name, rank, rankIndex, level, class, zone, note, officernote, online, status, classFileName = GetGuildRosterInfo(i)
		name = name and name:lower() or ""
		class = class and class:lower() or ""
		note = note and note:lower() or ""
		officernote = officernote and officernote:lower() or ""
		classFileName = classFileName and classFileName:lower() or ""
		rank = rank and rank:lower() or "" 
		zone = zone and zone:lower() or ""
		
		for k, v in pairs( self.filters["strings"] ) do
			if success and not name:match(v) and not class:match(v) and not classFileName:match(v) and
				not zone:match(v) and not note:match(v) and not officernote:match(v) and not rank:match(v) then 
					success = false
			end
		end
		if success then -- only continue if succesful
			for k, v in pairs( self.filters["levels"] ) do
				if success then
					if v["="] and level ~= v["="] then 
						success = false
					elseif v[">="] and level < v[">="] then
						success = false
					elseif v["<="] and level > v["<="] then
						success = false
					end
				end
			end
		end
		if success then
			table.insert(filteredMembers, i)
		end
	end
	
	-- now update the number of guildmembers to the new filtered list.
	numGuildMembers = #filteredMembers
	-- Scrollbar stuff
	-- I'll have to move this down and adjust widths after applying the filter
	local showScrollBar = nil
	if ( numGuildMembers > GUILDMEMBERS_TO_DISPLAY ) then
		showScrollBar = 1
	end

	if ( FriendsFrame.playerStatusFrame ) then
		-- Player specific info
		local guildOffset = FauxScrollFrame_GetOffset(GuildListScrollFrame)
		for i=1, GUILDMEMBERS_TO_DISPLAY, 1 do
			-- update guildIndex to the filtered index
			guildIndex = filteredMembers[guildOffset + i] or numGuildMembers + 1
			button = getglobal("GuildFrameButton"..i)
			button.guildIndex = guildIndex
			name, rank, rankIndex, level, class, zone, note, officernote, online, status, classFileName = GetGuildRosterInfo(guildIndex)
			if ( not online ) then
				buttonText = getglobal("GuildFrameButton"..i.."Name")
				buttonText:SetText(name)
				buttonText:SetTextColor(0.5, 0.5, 0.5)
				buttonText = getglobal("GuildFrameButton"..i.."Zone")
				buttonText:SetText(zone)
				buttonText:SetTextColor(0.5, 0.5, 0.5)
				buttonText = getglobal("GuildFrameButton"..i.."Level")
				buttonText:SetText(level)
				buttonText:SetTextColor(0.5, 0.5, 0.5)
				buttonText = getglobal("GuildFrameButton"..i.."Class")
				buttonText:SetText(class)
				buttonText:SetTextColor(0.5, 0.5, 0.5)
			else
				if ( classFileName ) then
					classTextColor = RAID_CLASS_COLORS[classFileName]
				else
					classTextColor = NORMAL_FONT_COLOR
				end

				buttonText = getglobal("GuildFrameButton"..i.."Name")
				buttonText:SetText(name)
				buttonText:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
				buttonText = getglobal("GuildFrameButton"..i.."Zone")
				buttonText:SetText(zone)
				buttonText:SetTextColor(1.0, 1.0, 1.0)
				buttonText = getglobal("GuildFrameButton"..i.."Level")
				buttonText:SetText(level)
				buttonText:SetTextColor(1.0, 1.0, 1.0)
				buttonText = getglobal("GuildFrameButton"..i.."Class")
				buttonText:SetText(class)
				buttonText:SetTextColor(classTextColor.r, classTextColor.g, classTextColor.b)
			end

			-- If need scrollbar resize columns
			if ( showScrollBar ) then
				getglobal("GuildFrameButton"..i.."Zone"):SetWidth(95)
			else
				getglobal("GuildFrameButton"..i.."Zone"):SetWidth(110)
			end

			-- Highlight the correct who
			if ( GetGuildRosterSelection() == guildIndex ) then
				button:LockHighlight()
			else
				button:UnlockHighlight()
			end
			
			if guildOffset + i  > numGuildMembers then
				button:Hide()
			else
				button:Show()
			end
		end
		
		GuildFrameGuildListToggleButton:SetText(PLAYER_STATUS)
		-- If need scrollbar resize column headers
		if ( showScrollBar ) then
			WhoFrameColumn_SetWidth(GuildFrameColumnHeader2, 105) -- , GuildFrameColumnHeader2)
			GuildFrameGuildListToggleButton:SetPoint("LEFT", "GuildFrame", "LEFT", 284, -67)
		else
			WhoFrameColumn_SetWidth(GuildFrameColumnHeader2, 120) -- , GuildFrameColumnHeader2)
			GuildFrameGuildListToggleButton:SetPoint("LEFT", "GuildFrame", "LEFT", 307, -67)
		end
		-- ScrollFrame update
		FauxScrollFrame_Update(GuildListScrollFrame, numGuildMembers, GUILDMEMBERS_TO_DISPLAY, FRIENDS_FRAME_GUILD_HEIGHT )
		
		GuildPlayerStatusFrame:Show()
		GuildStatusFrame:Hide()
	else
		-- Guild specific info
		local year, month, day, hour
		local yearlabel, monthlabel, daylabel, hourlabel
		local guildOffset = FauxScrollFrame_GetOffset(GuildListScrollFrame)

		for i=1, GUILDMEMBERS_TO_DISPLAY, 1 do
			guildIndex = filteredMembers[guildOffset + i] or numGuildMembers + 1
			button = getglobal("GuildFrameGuildStatusButton"..i)
			button.guildIndex = guildIndex
			name, rank, rankIndex, level, class, zone, note, officernote, online, status, classFileName = GetGuildRosterInfo(guildIndex)

			getglobal("GuildFrameGuildStatusButton"..i.."Name"):SetText(name)
			getglobal("GuildFrameGuildStatusButton"..i.."Rank"):SetText(rank)
			getglobal("GuildFrameGuildStatusButton"..i.."Note"):SetText(note)

			if ( online ) then
				if ( status == "" ) then
					getglobal("GuildFrameGuildStatusButton"..i.."Online"):SetText(GUILD_ONLINE_LABEL)
				else
					getglobal("GuildFrameGuildStatusButton"..i.."Online"):SetText(status)
				end

				if ( classFileName ) then
					classTextColor = RAID_CLASS_COLORS[classFileName]
				else
					classTextColor = NORMAL_FONT_COLOR
				end
				getglobal("GuildFrameGuildStatusButton"..i.."Name"):SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
				getglobal("GuildFrameGuildStatusButton"..i.."Rank"):SetTextColor(1.0, 1.0, 1.0)
				getglobal("GuildFrameGuildStatusButton"..i.."Note"):SetTextColor(1.0, 1.0, 1.0)
				getglobal("GuildFrameGuildStatusButton"..i.."Online"):SetTextColor(classTextColor.r, classTextColor.g, classTextColor.b)
			else
				getglobal("GuildFrameGuildStatusButton"..i.."Online"):SetText(GuildFrame_GetLastOnline(guildIndex))
				getglobal("GuildFrameGuildStatusButton"..i.."Name"):SetTextColor(0.5, 0.5, 0.5)
				getglobal("GuildFrameGuildStatusButton"..i.."Rank"):SetTextColor(0.5, 0.5, 0.5)
				getglobal("GuildFrameGuildStatusButton"..i.."Note"):SetTextColor(0.5, 0.5, 0.5)
				getglobal("GuildFrameGuildStatusButton"..i.."Online"):SetTextColor(0.5, 0.5, 0.5)
			end

			-- If need scrollbar resize columns
			if ( showScrollBar ) then
				getglobal("GuildFrameGuildStatusButton"..i.."Note"):SetWidth(70)
			else
				getglobal("GuildFrameGuildStatusButton"..i.."Note"):SetWidth(85)
			end

			-- Highlight the correct who
			if ( GetGuildRosterSelection() == guildIndex ) then
				button:LockHighlight()
			else
				button:UnlockHighlight()
			end

			if guildOffset + i  > numGuildMembers then
				button:Hide()
			else
				button:Show()
			end
		end
		
		GuildFrameGuildListToggleButton:SetText(GUILD_STATUS)
		-- If need scrollbar resize columns
		if ( showScrollBar ) then
			WhoFrameColumn_SetWidth(GuildFrameGuildStatusColumnHeader3, 75) -- , GuildFrameGuildStatusColumnHeader3)
			GuildFrameGuildListToggleButton:SetPoint("LEFT", "GuildFrame", "LEFT", 284, -67);
		else
			WhoFrameColumn_SetWidth(GuildFrameGuildStatusColumnHeader3, 90) -- , GuildFrameGuildStatusColumnHeader3)
			GuildFrameGuildListToggleButton:SetPoint("LEFT", "GuildFrame", "LEFT", 307, -67);
		end
		
		-- ScrollFrame update
		FauxScrollFrame_Update(GuildListScrollFrame, numGuildMembers, GUILDMEMBERS_TO_DISPLAY, FRIENDS_FRAME_GUILD_HEIGHT )

		GuildPlayerStatusFrame:Hide()
		GuildStatusFrame:Show()
	end
end

function GuildFilter:SetupGUI()
	if frame then return end
	
	GuildFrameLFGFrameRight:Hide()
	GuildFrameLFGFrameMiddle:Hide()
	GuildFrameLFGFrameLeft:Hide()
	GuildFrameLFGFrame:SetPoint("TOPRIGHT", -42, -32)
	
	local editbox = CreateFrame("EditBox", "GuildFilterSearchBox", GuildFrame, "InputBoxTemplate")	
	frame = editbox
	editbox:Hide()
	editbox:SetAutoFocus(false)
	editbox:SetWidth(220)
	editbox:SetHeight(20)
	editbox:ClearAllPoints()
	editbox:SetPoint("TOPRIGHT", -81, -50)
	
	editbox:SetScript("OnShow", function()
		if self.filter then editbox:SetText(self.filter) end
		if editbox:GetText() == "" then
			editbox:SetText(SEARCH)
		end 
	end )
	editbox:SetScript("OnHide", function()
		self.filter = nil
		editbox:SetText("")
	end )
	editbox:SetScript("OnEnterPressed", function() editbox:ClearFocus() end )
	editbox:SetScript("OnTextChanged", function() 
		if editbox:HasFocus() then
			GuildFilter:SetFilter(editbox:GetText())
		end
	end )
	editbox:SetScript("OnEditFocusLost", function()
		editbox:HighlightText(0,0)
		if editbox:GetText() == "" then editbox:SetText(SEARCH) end
	end )
	editbox:SetScript("OnEditFocusGained", function()
		editbox:HighlightText()
		if editbox:GetText() == SEARCH then editbox:SetText("") end
	end )
	
	local reset = CreateFrame("Button", "GuildFilterReset", GuildFrame)
	reset:SetWidth(39)
	reset:SetHeight(39)
	reset:SetPoint("TOPRIGHT", -45, -42)
	reset:SetNormalTexture("Interface\\Buttons\\CancelButton-Up")
	reset:SetPushedTexture("Interface\\Buttons\\CancelButton-Down")
	reset:SetHighlightTexture("Interface\\Buttons\\CancelButton-Highlight", "ADD")
	
	reset:SetScript("OnClick", function()
		if editbox:HasFocus() then
			editbox:SetText("")
		else
			editbox:SetText(SEARCH)
		end
		GuildFilter:SetFilter("")
	end )
end

function GuildFilter:ShowGUI()
	self:SetupGUI()
	frame:Show()
end

function GuildFilter:HideGUI()
	if not frame then return end
	frame:Hide()
end

